int ans=1; for(re int i=1;i<=tmp;i++){ for(re int j=i+1;j<=tmp;j++){ while(a[j][i]){ int t=a[i][i]/a[j][i]; for(re int k=i;k<=tmp;k++)a[i][k]=(a[i][k]-a[j][k]*t%mod+mod)%mod; swap(a[i],a[j]); ans*=-1; } } ans=(ans*a[i][i]%mod+mod)%mod; } return (ans%mod+mod)%mod;
这里同时给出对于模数是质数时,求解行列式的方法:
inlineintdet(){ int ans=1; for(re int i=1;i<=tmp;i++){ for(re int j=i;j<=tmp;j++){ if(a[j][i]){ swap(a[i],a[j]); if(i!=j)ans=mod-ans; break; } }
int t=qpow(a[i][i],mod-2);
for(re int j=i+1;j<=tmp;j++){ if(a[j][i]){ for(re int k=tmp;k>=i;k--){ a[j][k]=(a[j][k]-a[i][k]*t%mod*a[j][i]%mod+mod)%mod; } } } }
for(re int i=1;i<=tmp;i++)ans=ans*a[i][i]%mod;
return ans; }
需要处理一下负数情况,否则会出问题:
inlinevoidcheck(){ for(re int i=1;i<=n;i++){ for(re int j=1;j<=n;j++){ if(a[i][j]<0) a[i][j]+=mod; } } }
对于本题,并不是所有的点都可以用来求行列式,只有不是墙的点才能放进矩阵。
否则根据上面的性质:如果其中有个一元素为 $0$ 则整体为 $0$ 。
就会直接 WA 了。
对于加边,只加向下或者向右的边,可以保证不重复。
for(re int i=1;i<=n;i++){ for(re int j=1;j<=m;j++){ cin>>a[i][j]; if(a[i][j]=='.')id[i][j]=++cnt;//用cnt来重新编号 } }
inlineintdet(){//高斯消元与求行列式 int ans=1; for(re int i=1;i<=tmp;i++){ for(re int j=i+1;j<=tmp;j++){ while(a[j][i]){//辗转相除 int t=a[i][i]/a[j][i]; for(re int k=i;k<=tmp;k++){ a[i][k]=(a[i][k]-a[j][k]*t%mod+mod)%mod;
for(re int i=1;i<=n;i++){//构造邻接矩阵 for(re int j=1;j<=m;j++){ if(id[i][j]&&id[i][j-1])add(id[i][j],id[i][j-1]); if(id[i][j]&&id[i-1][j])add(id[i][j],id[i-1][j]); } }
for(re int i=1;i<=cnt;i++){//构造度数矩阵 for(re int j=1;j<=cnt;j++){ if(A.a[i][j]) D.a[i][i]++; } }
W=D-A;//两者作差得到基尔霍夫矩阵(拉普拉斯矩阵)
W.tmp=--cnt;//除掉最后一行与最后一列
/*for(re int i=1;i<=cnt;i++){ for(re int j=1;j<=cnt;j++){ cout<<W.a[i][j]<<" "; } cout<<endl; }*/